package edu.hawaii.examschd.modules.CouchDB;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.StringTokenizer;
import edu.hawaii.examschd.Core;
import edu.hawaii.examschd.myClass;
import edu.hawaii.examschd.modules.ExamScheduler;
import edu.hawaii.examschd.modules.Module;

public class CouchDB implements ExamScheduler, Module {

  private boolean DEBUG = false;
  private boolean VERBOSE = false;
  CouchDBClient client;
  String url_crn = "/uhm/_design/uhm/_view/crn?key=\"";
  String url_exam = "/uhm/_design/uhm/_view/exam?key=\"";

  /**
   * Constructor
   */
  public CouchDB() {
    client = new CouchDBClient();
  }

  /**
   * Initilize on load
   */
  @Override
  public int load() {

    print("CouchDb: Loaded");
    client = new CouchDBClient();
    return 0;
  }

  /**
   * Unload Module
   */
  @Override
  public int unload() {
    print("CouchDB: Unloaded");
    client.close();
    return 0;
  }

  /**
   * Return the module name;
   */
  @Override
  public String getName() {
    return "CouchDB";
  }

  /**
   * Get the exam time from the database by CRN number.
   * 
   * @param crn CRN number of the class
   * @return result A string containing the exam time
   */
  @Override
  public String get_by_crn_as_str(int crn) {
    String output = null;
    Calendar cal = get_by_crn_as_cal(crn);
    output = cal_to_sdf_string(cal);
    return output;
  }

  /**
   * Get the exam time from the database by CRN number.
   * 
   * @param crn CRN number of the class
   * @return cal Calendar object containing exam data.
   */
  @Override
  public Calendar get_by_crn_as_cal(int crn) {

    Calendar cal;
    String message = url_crn + crn + "\"";
    if (VERBOSE) {
      System.out.println(message);
    }
    String result = client.send(message);
    if (VERBOSE) {
      System.out.println(result);
    }
    cal = get_exam_by_times(result);
    return cal;
  }

  /**
   * Get the exam time for multiple classes from the database by CRN.
   * 
   * @param crn CRN numbers of the class
   * @return cals Calendar objects.
   */
  @Override
  public Calendar[] get_by_crn_as_cals(int[] crns) {
    String temp = null;
    Calendar[] cals = new Calendar[crns.length];
    int i = 0;
    for (int crn : crns) {
      temp = client.send(url_crn + crn + "\"");
      cals[i] = get_exam_by_times(temp);
      i++;
    }
    return cals;
  }

  /**
   * Get multiple exam times by their CRN
   * 
   * @param crns list of CRN numbers to look up
   * @return data list of exam strings
   */
  @Override
  public String[] get_by_crn_as_strs(int[] crns) {
    String[] data = new String[crns.length];
    int i = 0;
    for (int crn : crns) {
      data[i] = get_by_crn_as_str(crn);
      i++;
    }
    return data;
  }

  /**
   * Get the Dept and class number (e.g. ICS 414) as a string
   * 
   * @param crn CRN number for the class
   * @return class string (e.g. ENG 271)
   */
  public String get_class_name(int crn) {
    String result = "";
    String temp;
    String query = client.send(url_crn + crn + "\"");
    StringTokenizer stok = new StringTokenizer(query, ",");
    temp = stok.nextToken();
    result = result + stok.nextToken();
    result = result + " ";
    result = result + stok.nextToken();

    return result;

  }

  /**
   * Sync "Global" Variables to the module.
   * 
   * @param d Debug flag
   * @param v Verbose flag
   */
  @Override
  public int syncVars(boolean d, boolean v) {
    DEBUG = d;
    VERBOSE = v;
    return 1;
  }

  @Override
  public String get_class_by_crn_as_str(int crn) {
    String result = "";
    String query = client.send(url_crn + crn + "\"");
    result = query.substring(6);
    return result;
  }

  @Override
  public String[] get_classes_by_crn_as_str(int[] crns) {
    String[] result = new String[crns.length];
    int i = 0;
    for (int crn : crns) {
      result[i] = get_class_by_crn_as_str(crn);
      i++;
    }
    return result;
  }

  @Override
  public myClass get_all_by_crn(int crn) {
    String dept = "";
    String days = "";
    String temp = "";
    int num = 0;
    int start = 0;
    int end = 0;
    Calendar exam = get_by_crn_as_cal(crn);
    temp = get_class_by_crn_as_str(crn);
    StringTokenizer st = new StringTokenizer(temp, ",");
    dept = st.nextToken();
    num = Integer.parseInt(st.nextToken());
    days = st.nextToken();
    start = Integer.parseInt(st.nextToken());
    end = Integer.parseInt(st.nextToken());

    myClass output = new myClass(dept, num, days, start, end, exam);
    return output;
  }

  @Override
  public myClass[] get_all_by_crn(int[] crns) {
    myClass[] output = new myClass[crns.length];
    int i = 0;
    for (int crn : crns) {
      output[i] = get_all_by_crn(crn);
      i++;
    }
    return null;
  }

  private String cal_to_sdf_string(Calendar cal) {
    DateFormat df = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    String output = null;
    output = df.format(cal.getTime());
    return output;
  }

  public Calendar get_exam_by_times(String result) {
    String days;
    String stime;
    String etime;
    String line;
    String temp;
    int symbol = 0;
    if (result == null) {
      return null;
    }
    StringTokenizer stok = new StringTokenizer(result, ",");
    temp = stok.nextToken();
    temp = stok.nextToken();
    temp = stok.nextToken();
    days = stok.nextToken();
    stime = stok.nextToken();
    etime = stok.nextToken();
    Calendar cal = new GregorianCalendar();
    Locale locale = Locale.getDefault();

    // hard-coded Symbol table since this does not seem to change
    // from semester to semester.
    if (days.equals("MW") || days.equals("MF") || days.equals("MWF") || days.equals("WF")) {
      if (stime.compareTo("0830") < 0) {
        symbol = 1;
      }
      else if (stime.compareTo("0930") < 0) {
        symbol = 2;
      }
      else if (stime.compareTo("1030") < 0) {
        symbol = 3;
      }
      else if (stime.compareTo("1130") < 0) {
        symbol = 4;
      }
      else if (stime.compareTo("1230") < 0) {
        symbol = 5;
      }
      else if (stime.compareTo("1330") < 0) {
        symbol = 6;
      }
      else if (stime.compareTo("1430") < 0) {
        symbol = 7;
      }
      else if (stime.compareTo("1530") < 0) {
        symbol = 8;
      }
      else if (stime.compareTo("1630") < 0) {
        symbol = 9;
      }
      else if (stime.compareTo("1629") > 0) {
        symbol = 10;
      }

    }
    else if (days.equals("R") || days.equals("T") || days.equals("TR")) {
      if (stime.compareTo("0900") < 0) {
        symbol = 11;
      }
      else if (stime.compareTo("1030") < 0) {
        symbol = 12;
      }
      else if (stime.compareTo("1200") < 0) {
        symbol = 13;
      }
      else if (stime.compareTo("1330") < 0) {
        symbol = 14;
      }
      else if (stime.compareTo("1500") < 0) {
        symbol = 15;
      }
      else if (stime.compareTo("1630") < 0) {
        symbol = 16;
      }
      else if (stime.compareTo("1629") > 0) {
        symbol = 17;
      }
    }
    // now that we have the symbol look it up in the database
    if (symbol == 0) {
      print("Exam time is either nonstandard or missing, pleas consult the Instructor");
    }
    line = client.send(url_exam + symbol + "\"");
    line = line.substring(3);
    stok = new StringTokenizer(line, ",");
    int year = Integer.parseInt(stok.nextToken());
    int month = Integer.parseInt(stok.nextToken()) - 1;
    int date = Integer.parseInt(stok.nextToken());
    temp = stok.nextToken();
    int hourOfDay = Integer.parseInt(temp.substring(0, 2));
    int minute = Integer.parseInt(temp.substring(2));
    cal.set(year, month, date, hourOfDay, minute);
    return cal;
  }

  /**
   * Consistent printing
   */
  private void print(String s) {
    Core.print(s);
  }

  /**
   * Testing method
   */
  public static void main(String[] args) {
    CouchDB cdb = new CouchDB();
    String line = cdb.client.send("/uhm/_design/uhm/_view/crn?key=\"84850\"");
    System.out.println(line);
    System.out.println(cdb.get_class_name(84850));
    System.out.println(cdb.get_class_by_crn_as_str(85833));
  }
}